﻿//-----------------------------------------------------------------------
// <copyright>
// This file is subject to the terms and conditions of the Microsoft Public License (MS-PL).
// See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL for more details.
// </copyright>
//----------------------------------------------------------------------- 
using System;
using System.Collections.Generic;
using System.Windows;

namespace Fulcrum.ControlGenerator
{
    public enum PropertyChangedEventType
    {
        RoutedEvent,
        DotNetEvent
    }

    public class ControlGeneratorGenerationDataContext : GenerationDataContext
    {
        string name;
        string outputLocation;
        SortedDictionary<string, string> usingNamespaces;
        SortedDictionary<string, TemplatePartDataContext> templateParts;
        SortedDictionary<string, RoutedCommandDataContext> routedCommands;
        SortedDictionary<string, RoutedCommandBindingDataContext> routedCommandBindings;
        SortedDictionary<string, RoutedEventDataContext> routedEvents;
        SortedDictionary<string, DependencyPropertyDataContext> dependencyProperties;
        SortedDictionary<string, AttachedDependencyPropertyDataContext> attachedDependencyProperties;

        private ControlGeneratorGenerationDataContext()
        {
            this.usingNamespaces = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            this.templateParts = new SortedDictionary<string, TemplatePartDataContext>(StringComparer.OrdinalIgnoreCase);
            this.routedCommands = new SortedDictionary<string, RoutedCommandDataContext>(StringComparer.OrdinalIgnoreCase);
            this.routedCommandBindings = new SortedDictionary<string, RoutedCommandBindingDataContext>(StringComparer.OrdinalIgnoreCase);
            this.routedEvents = new SortedDictionary<string, RoutedEventDataContext>(StringComparer.OrdinalIgnoreCase);
            this.dependencyProperties = new SortedDictionary<string, DependencyPropertyDataContext>(StringComparer.OrdinalIgnoreCase);
            this.attachedDependencyProperties = new SortedDictionary<string, AttachedDependencyPropertyDataContext>(StringComparer.OrdinalIgnoreCase);

            //
            // Common namespaces needed
            //
            AddUsingNamespace("System");
            AddUsingNamespace("System.ComponentModel");
            AddUsingNamespace("System.Windows");
        }

        public ControlGeneratorGenerationDataContext(IControlGeneratorConfiguration config, IControlConfiguration controlConfig) :
            this()
        {
            //
            // Global settings
            //
            this.Company = config.Company;
            this.Copyright = config.Copyright;
            this.Namespace = config.Namespace;
            this.OptionalTemplatePartFactory = config.OptionalTemplatePartFactory;
            this.RoutedPropertyEventArgsFactory = config.RoutedPropertyEventArgsFactory;
            this.TemplatePartFactory = config.TemplatePartFactory;

            //
            // control settings
            //
            this.AutomationPeerArguments = controlConfig.AutomationPeerArguments;
            this.AutomationPeerName = controlConfig.AutomationPeerName;
            this.HasAutomationPeer = controlConfig.HasAutomationPeer;
            this.LocalizationCategory = controlConfig.LocalizationCategory;
            this.LocalizationModifiability = controlConfig.LocalizationModifiability;
            this.LocalizationReadability = controlConfig.LocalizationReadability;
            this.SetName(controlConfig.Name);

            if (false == String.IsNullOrEmpty(controlConfig.Namespace))
            {
                this.Namespace = controlConfig.Namespace;
            }

            this.SetOutputPath(controlConfig.Location);
            this.OverrideStyleMetadata = controlConfig.OverrideStyleMetadata;
            this.PropertyChangedEventType = controlConfig.PropertyChangedEventType;
            this.Remarks = controlConfig.Remarks;
            this.Summary = controlConfig.Summary;

            this.AddUsingNamespaces(controlConfig.UsingNamespaces);

            foreach (var templatePart in controlConfig.TemplateParts)
            {
                var templatePartDataContext = new TemplatePartDataContext(templatePart);
                this.AddTemplatePart(templatePartDataContext);
            }

            foreach (var commandBinding in controlConfig.RoutedCommandBindings)
            {
                var commandBindingDataContext = new RoutedCommandBindingDataContext(commandBinding);
                this.AddRoutedCommandBinding(commandBindingDataContext);
            }

            foreach (var command in controlConfig.RoutedCommands)
            {
                var commandBindingDataContext = new RoutedCommandBindingDataContext(command, this.Name);
                var commandDataContext = new RoutedCommandDataContext(commandBindingDataContext);

                this.AddRoutedCommand(commandDataContext);
                this.AddRoutedCommandBinding(commandBindingDataContext);
            }

            foreach (var routedEvent in controlConfig.RoutedEvents)
            {
                var routedEventDataContext = new RoutedEventDataContext(routedEvent);
                this.AddRoutedEvent(routedEventDataContext);
            }

            foreach (var dependencyProperty in controlConfig.DependencyProperties)
            {
                var dependencyPropertyDataContext = new DependencyPropertyDataContext(dependencyProperty);
                this.AddDependencyProperty(dependencyPropertyDataContext);
            }

            foreach (var attachedDependencyProperty in controlConfig.AttachedDependencyProperties)
            {
                var attachedDependencyPropertyDataContext = new AttachedDependencyPropertyDataContext(attachedDependencyProperty);
                this.AddAttachedDependencyProperty(attachedDependencyPropertyDataContext);
            }
        }

        public override string Name
        {
            get
            {
                return this.name;
            }
        }

        private void SetName(string name)
        {
            this.name = name;
        }

        public override string TemplateFileName
        {
            get
            {
                return "ControlGenerator.t4";
            }
        }

        public override string OutputFileName
        {
            get
            {
                return String.Format("{0}.Generated", this.Name);
            }
        }

        public override string OutputPath
        {
            get
            {
                return this.outputLocation;
            }
        }

        private void SetOutputPath(string outputPath)
        {
            this.outputLocation = outputPath;
        }

        //
        // "Global" settings
        //
        public string Company
        {
            get;
            private set;
        }

        public string Copyright
        {
            get;
            private set;
        }

        public string Namespace
        {
            get;
            private set;
        }

        public string RoutedPropertyEventArgsFactory
        {
            get;
            private set;
        }

        public string TemplatePartFactory
        {
            get;
            private set;
        }

        public string OptionalTemplatePartFactory
        {
            get;
            private set;
        }


        //
        // Control settings
        //
        public string Summary
        {
            get;
            private set;
        }

        public string Remarks
        {
            get;
            private set;
        }

        public ICollection<string> UsingNamespaces
        {
            get
            {
                return this.usingNamespaces.Values;
            }
        }

        private void AddUsingNamespaces(ICollection<string> namespaces)
        {
            foreach (var @namespace in namespaces)
            {
                AddUsingNamespace(@namespace);
            }
        }

        private void AddUsingNamespace(string @namespace)
        {
            this.usingNamespaces[@namespace] = @namespace;
        }

        public PropertyChangedEventType PropertyChangedEventType
        {
            get;
            private set;
        }

        public bool HasAutomationPeer
        {
            get;
            private set;
        }

        public string AutomationPeerName
        {
            get;
            private set;
        }

        public string AutomationPeerArguments
        {
            get;
            internal set;
        }

        public bool OverrideStyleMetadata
        {
            get;
            private set;
        }

        public LocalizationCategory LocalizationCategory
        {
            get;
            private set;
        }

        public Modifiability LocalizationModifiability
        {
            get;
            private set;
        }

        public Readability LocalizationReadability
        {
            get;
            private set;
        }

        public ICollection<TemplatePartDataContext> TemplateParts
        {
            get
            {
                return this.templateParts.Values;
            }
        }

        private void AddTemplatePart(TemplatePartDataContext templatePart)
        {
            this.templateParts.Add(templatePart.Name, templatePart);
        }

        public ICollection<DependencyPropertyDataContext> DependencyProperties
        {
            get
            {
                return this.dependencyProperties.Values;
            }
        }

        private void AddDependencyProperty(DependencyPropertyDataContext dependencyProperty)
        {
            this.dependencyProperties.Add(dependencyProperty.Name, dependencyProperty);
        }

        public ICollection<AttachedDependencyPropertyDataContext> AttachedDependencyProperties
        {
            get
            {
                return this.attachedDependencyProperties.Values;
            }
        }

        private void AddAttachedDependencyProperty(AttachedDependencyPropertyDataContext dependencyProperty)
        {
            this.attachedDependencyProperties.Add(dependencyProperty.Name, dependencyProperty);
        }

        public ICollection<RoutedCommandDataContext> RoutedCommands
        {
            get
            {
                return this.routedCommands.Values;
            }
        }

        private void AddRoutedCommand(RoutedCommandDataContext routedCommand)
        {
            AddUsingNamespace("System.Windows.Input");

            this.routedCommands.Add(routedCommand.Name, routedCommand);
        }

        public ICollection<RoutedCommandBindingDataContext> RoutedCommandBindings
        {
            get
            {
                return this.routedCommandBindings.Values;
            }
        }

        private void AddRoutedCommandBinding(RoutedCommandBindingDataContext routedCommandBinding)
        {
            AddUsingNamespace("System.Windows.Input");

            this.routedCommandBindings.Add(routedCommandBinding.Name, routedCommandBinding);
        }

        public ICollection<RoutedEventDataContext> RoutedEvents
        {
            get
            {
                return this.routedEvents.Values;
            }
        }

        private void AddRoutedEvent(RoutedEventDataContext routedEvent)
        {
            this.routedEvents.Add(routedEvent.Name, routedEvent);
        }

    }
}
